﻿using System;
using System.Disposables;
using System.IO;
using System.Linq;
using System.Text;
using Collab.Modules.Editing.Interfaces;
using Collab.Services.Remote.Entities;
using System.Threading;

namespace Collab.Modules.Editing
{
    public class VirtualEditBuffer : IEditBuffer
    {
        private readonly CompositeDisposable disposable = new CompositeDisposable();
        private readonly StringBuilder buffer = new StringBuilder();
        private readonly object editTag = new object();
        private int revision = 0;
        private readonly ChangeProcessor changeProcessor = new ChangeProcessor();
        private readonly string solutionPath;

        public VirtualEditBuffer(Guid userID, string solutionPath, string documentName, DocumentSnapshot document = null)
        {
            this.UserId = userID;
            this.DocumentName = documentName;
            this.solutionPath = solutionPath;

            if (document != null)
            {
                this.buffer.Append(document.Text);
                this.revision = document.Revision;
            }
            else
            {
                //Load the document;
                string path = Path.Combine(solutionPath, documentName);
                try
                {
                    this.buffer.Append(File.ReadAllText(path));
                }
                catch (FileNotFoundException)
                {

                    for (int i = 0; i < 4; i++)
                    {
                        Thread.Sleep(5000);
                        if (File.Exists(path))
                            this.buffer.Append(File.ReadAllText(path));
                    }

                }
            }

            this.disposable.Add(this.changeProcessor.Subscribe(update =>
                {
                    update.Changes.Run(change =>
                    {
                        this.buffer.Remove(change.OldStart, change.OldEnd - change.OldStart);
                        this.buffer.Insert(change.OldStart, change.Text);
                    });
                }));
        }

        #region IEditBuffer Members

        public Guid UserId { get; private set; }

        public string DocumentName { get; private set; }

        public DocumentSnapshot CurrentSnapshot
        {
            get
            {
                return new DocumentSnapshot() { Text = this.buffer.ToString(), Revision = this.revision };
            }
        }


        #endregion

        #region IObserver<BufferUpdate> Members

        public void OnCompleted()
        {
            changeProcessor.OnCompleted();
        }

        public void OnError(Exception error)
        {
            changeProcessor.OnError(error);
        }

        public void OnNext(BufferUpdate update)
        {
            changeProcessor.OnNext(update);
            ++this.revision;
        }

        #endregion

        #region IObservable<BufferUpdate> Members

        public IDisposable Subscribe(IObserver<BufferUpdate> observer)
        {
            return changeProcessor.Subscribe(observer);
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            this.changeProcessor.Dispose();
        }

        #endregion

        #region IEditBuffer Members


        public int Revision
        {
            get { return this.changeProcessor.Revision; }
        }

        #endregion
    }
}
